#include "my_modbus_rtu_master.h"
#include <QDebug>
/*
    ------------------------README------------------------------



*/

my_modbus_rtu_master::my_modbus_rtu_master()
{

}


QByteArray my_modbus_rtu_master::MessageInformation(QByteArray requestInfo,QString inputData)
{
    messageInfo = requestInfo;

    switch(requestInfo[1])
    {
    case 0x01:
    {
        return MessageBuildRead(requestInfo);
        break;
    }
    case 0x03:
        return MessageBuildRead(requestInfo);
        break;
    case 0x0f:
    case 0x10:
        QByteArray Data;
        if(requestInfo[1] == 0x0f)
        {
            Data  = InputCoils(inputData);
        }
        else if(requestInfo[1] == 0x10)
        {
            Data  = InputRegisters(inputData);
        }
        return MessageBuildWrite(requestInfo,Data);
        break;
    }
    return 0;
}
//报文构建
QByteArray my_modbus_rtu_master::MessageBuildRead(QByteArray inputData)
{
    QByteArray data;
    data.resize(8 - 2);
    data[0]=inputData[0];
    data[1]=inputData[1];
    data[2]=(inputData[2]) >> 8;
    data[3]=(inputData[2]) & 0xff;
    data[4]=(inputData[3]) >> 8;
    data[5]=(inputData[3]) & 0xff;

    quint16 CrcNumber = CRC16Modbus(data,0);

    data.resize(8);

    data[6]=CrcNumber >> 8;
    data[7]=CrcNumber & 0xff;

    return data;
}

//寄存器数据处理
QByteArray my_modbus_rtu_master::InputRegisters(QString inputData)
{
    int num = messageInfo[3];//requestInfo[3].toInt();
    //需要的字节数，一个寄存器需要2字节

    qDebug()<<num;
    int numOfByte = 2*num;
    //创建寄存器输入数组
    QByteArray RegistersInputArr;
    RegistersInputArr.resize(numOfByte);

    //获取输入框内的字符串,默认为空
    QString writeRegister = nullptr;

    QString writeRegister1 = inputData;


    for(int res = 0;res<num;res++)
    {

        writeRegister = writeRegister1.section(QRegExp("[/-]"),res+1,res+1);
        qDebug()<<writeRegister;
        //转化为2进制字符串，不足补0，凑足16位
        writeRegister = QString("%1").arg(quint16(writeRegister.toInt(nullptr,10)),16,2,QLatin1Char('0'));
        //前8位为一个字节
        RegistersInputArr[2*res] = writeRegister.mid(0,8).toInt(nullptr,2);
        //后8位为一个字节
        RegistersInputArr[2*res + 1] = writeRegister.mid(8,8).toInt(nullptr,2);
    }

    return RegistersInputArr;
}

QByteArray my_modbus_rtu_master::MessageBuildWrite(QByteArray requestInfo,QByteArray Data)
{
    //声明字节数组
    // 设备地址+功能码+起始地址+数量+字节数+n字节数据+差错校验
    // 1+1+2+2+1+n+2

    QByteArray data;
    data.resize(8 - 1);
    data[0]=requestInfo[0];
    data[1]=requestInfo[1];
    data[2]=requestInfo[2] >> 8;
    data[3]=requestInfo[2] & 0xff;
    data[4]=requestInfo[3] >> 8;
    data[5]=requestInfo[3] & 0xff;
    data[6]=quint8(Data.size());

    QByteArray Message;
    Message.append(data);
    Message.append(Data);

    quint16 CrcNumber = CRC16Modbus(Message,0);

    Message.append(CrcNumber >> 8);
    Message.append(CrcNumber & 0xff);

    return Message;

}

//线圈数据处理
QByteArray my_modbus_rtu_master::InputCoils(QString inputCoild)
{
    QString writeCoils = inputCoild;
    //字符串长度，默认为0
    int writeCoilsLength = writeCoils.length();

    //求出字节数
    int numOfByte = (writeCoilsLength + 7) / 8;

    //对字符串空位进行补0
    for(int i = 1; i <= (8*numOfByte - writeCoilsLength); i++)
    {
        writeCoils += '0';
    }

    QByteArray coilsInputArr;
    coilsInputArr.resize(numOfByte);

    //字节：1字节*numOfByte
    for(int i = 0; i < numOfByte; i++)
    {
        //对8位1字节进行反转处理
        QString vector = writeCoils.mid((8 * i),8);
        //字节反转
        byteReverse(vector);
        //存入请求报文数组
        coilsInputArr[i] = vector.toInt(nullptr,2);
    }

    return coilsInputArr;
}

//字节反转
void my_modbus_rtu_master::byteReverse(QString &coils)
{

    QChar temp;

    for(int i=0; i < 4; i++)
    {
        temp = coils[i];
        coils[i] = coils[8-i-1];
        coils[8-i-1] = temp;
    }
}


//接收响应报文解析
int my_modbus_rtu_master::AnalysisResponseMessage(QByteArray responseMessage,QByteArray RequestMessageArray)
{
    //长度判断：最大长度、最小长度
    if(responseMessage.size() > 255)
    {
        return MESSAGE_LENGTH_OVERLONG;
    }
    if(responseMessage.size() < 5)
    {
        return MESSAGE_LENGTH_HEATING;
    }
    //从机地址是否正确
    if(RequestMessageArray[0] != responseMessage[0])
    {
        return SLAVE_ADDRESS_ERROR;
    }
    //是否是异常报文

    if(responseMessage.size() == 5)
    {
        quint8 FuncCodeNumber;
        FuncCodeNumber = quint8(responseMessage.at(1));
        if(FuncCodeNumber != 129 && FuncCodeNumber != 131 && FuncCodeNumber != 143 && FuncCodeNumber != 144)
        {
            return MESSAGE_LENGTH_ERROR;
        }
        //判断差错码是否正常
        quint8 ErrorCode;
        ErrorCode = quint8(responseMessage.at(2));
        if(ErrorCode != 1 && ErrorCode != 2 && ErrorCode != 3)
        {
           return ERROR_CODE_ANOMALY;
        }
        //判断校验码是否正常
        quint16 AbnormalMessageCRC;
        AbnormalMessageCRC = BondTwoUint8ToUint16(quint8(responseMessage[3]),quint8(responseMessage[4]));
        QByteArray AbnormalMessageData;
        AbnormalMessageData = responseMessage.left(3);
        quint16 AbnormalMessageCrcCheck;
        AbnormalMessageCrcCheck = CRC16Modbus(AbnormalMessageData,0);
        if(AbnormalMessageCRC != AbnormalMessageCrcCheck)
        {
            return CHCEK_CODE_ERROR;
        }
        //正常异常响应报文
        QString AbnormalFuncCode ;
        QByteArray temp;
        temp.append(responseMessage[2]);
        AbnormalFuncCode = ByteArrayToString(temp,temp.size(),1);
        dataPtr = AbnormalFuncCode;
        return DATA_RETURN;
    }
    //功能码是否合法
    quint8 responseMessageFuncCode;
    responseMessageFuncCode = quint8(responseMessage[1]);
    if(responseMessageFuncCode != 1 && responseMessageFuncCode != 3 && responseMessageFuncCode != 15 && responseMessageFuncCode !=16)
    {
        return FUNCTION_ERROR;
    }
    //请求与响应的功能码是否一致
    quint8 RequestMessageArrayFuncCode;
    RequestMessageArrayFuncCode = quint8(RequestMessageArray[1]);
    if(RequestMessageArrayFuncCode != responseMessageFuncCode)
    {
        return WITH_REQUEST_MISTAKE;
    }

    //CRC差错校验
    quint16 responseMessageCRC;
    responseMessageCRC = CRC16Modbus(responseMessage.mid(0,responseMessage.size()-2),0);
    quint16 CrcCheck;
    CrcCheck = BondTwoUint8ToUint16(quint8(responseMessage[responseMessage.size()-2]),quint8(responseMessage[responseMessage.size()-1]));

    if(CrcCheck != responseMessageCRC)
    {
        return RESPONSE_CHCEK_ERROR;
    }

    //与请求报文比较
    switch(responseMessageFuncCode)
    {
    case 1:
    case 3:
        //响应报文中 数据域字节数 与 实际数据所用字节总数 是否一致
        quint8 responseMessageDataNumber;
        responseMessageDataNumber = responseMessage.size() - 5;
        if(quint8(responseMessage[2]) != responseMessageDataNumber)
        {
            return BYTESIZE_MISTAKE;
        }
        break;
    case 15:
    case 16:
        //起始地址是否一致
        quint16 responseMessageBeginAddress;
        responseMessageBeginAddress=BondTwoUint8ToUint16(quint8(responseMessage[2]),quint8(responseMessage[3]));
        quint16 RequestMessageArrayBeginAddress;
        RequestMessageArrayBeginAddress=BondTwoUint8ToUint16(quint8(RequestMessageArray[2]),quint8(RequestMessageArray[3]));
        if(responseMessageBeginAddress != RequestMessageArrayBeginAddress)
        {
            return START_ADDRESS_ERROR;
        }
        //查询数量是否一致
        quint16 responseMessageNumber;
        responseMessageNumber=BondTwoUint8ToUint16(quint8(responseMessage[4]),quint8(responseMessage[5]));
        quint16 RequestMessageArrayNumber;
        RequestMessageArrayNumber=BondTwoUint8ToUint16(quint8(RequestMessageArray[4]),quint8(RequestMessageArray[5]));
        if(responseMessageNumber != RequestMessageArrayNumber)
        {
            return NUMBER_ERROR;
        }
        break;
    }

    //无异常，显示查询报文数据
    qDebug()<<"test";
    QByteArray DataArray;
    DataArray = responseMessage.mid(3,responseMessage.size() - 5);
    //请求报文 起始地址
    quint16 BeginAddress;
    BeginAddress = BondTwoUint8ToUint16(quint8(RequestMessageArray[2]),quint8(RequestMessageArray[3]));
    //请求报文 数据个数
    quint16 DataNumber;
    DataNumber = BondTwoUint8ToUint16(quint8(RequestMessageArray[4]),quint8(RequestMessageArray[5]));
    QString res;
    switch(responseMessageFuncCode)
    {
    case 1:
        res = ByteArrayToBinString(DataArray,DataNumber);
        dataPtr = res;
        return DATA_RETURN_COIL;
        break;
    case 3:
        res = ByteArrayToDecString(DataArray);
        dataPtr = res;
        return DATA_RETURN_REGISTER;
        break;
    }

    return 1000;
}

//16进制数组转字符串为pattern=0不加空格，pattern=1位加空格
QString my_modbus_rtu_master::ByteArrayToString(QByteArray HexByteArr,int ConvertLen, int pattern = 0)
{
    //获得目标数组大小
    int HexByteArrSize = HexByteArr.size();
    //判断长度是否合法，如果长度大于数组长度，则设为数组长度，小于0则设置为0
    if(ConvertLen > HexByteArrSize)
    {
        ConvertLen = HexByteArrSize;
    }
    else if(ConvertLen < 0)
    {
        ConvertLen = 0;
    }

    //声明目标字符串
    QString readMes = nullptr;

    for(int i = 0; i < ConvertLen; i++)
    {
        readMes += QString("%1").arg(quint8(HexByteArr.at(i)),2,16,QLatin1Char('0'));
        //判断转换的模式
        if(pattern == 1)
        {
            readMes += " ";
        }
    }

    //返回转化后的十六进制字符串
    return readMes;
}

quint16 my_modbus_rtu_master::BondTwoUint8ToUint16(quint8 preNum, quint8 afterNum)
{
    quint16 bondNum = (preNum << 8) | afterNum;
    return bondNum;
}

//字节数组转二进制字符串
QString my_modbus_rtu_master::ByteArrayToBinString(QByteArray DataArray,quint16 DataNumber)
{
    QString dataObtained;
    //取出所读的多个线圈，并显示，数据从第九位开始
    for(int i = 0; i < DataArray.size(); i++)
    {
        QString str = QString::number(quint8(DataArray.at(i)),2);
        str = QString("%1").arg(quint8(str.toInt(nullptr,2)),8,2,QChar('0'));
        byteReverse(str);
        dataObtained += str;
    }
    //去除填充的0位，读出请求报文请求的线圈数
    dataObtained = dataObtained.left(DataNumber);

    return dataObtained;
}

//字节数组转十进制字符串
QString my_modbus_rtu_master::ByteArrayToDecString(QByteArray DataArray)
{
    QString dataObtained;

    for(int i = 0; i < DataArray.size(); i += 2)
    {
        dataObtained += QString::number(BondTwoUint8ToUint16(quint8(DataArray.at(i)),quint8(DataArray.at(i+1))));
        dataObtained += " ";
    }

    return dataObtained.left(dataObtained.size()-1);
}
